#pragma once

#include <cstddef>

namespace AVUI {

class WeakReference;
class Type;
class Object;

template<class T>
class TFieldScopeLock
{
public:
    TFieldScopeLock(T* pT) : m_pT(pT)
    {
        while(AVUI_INTERLOCKED_COMPARE_EXCHANGE(pT->m_lockField, 1, 0))
        {
            AVUI_YIELD();
        }
    }
    ~TFieldScopeLock()
    {
        m_pT->m_lockField = 0;
    }
private:
    T* m_pT;
};

class ObjectLock
{
public:
    ObjectLock(Object* pObject);
    ~ObjectLock();
private:
    Object* m_p;
};

class Object
{
    template<class T>
    friend class TFieldScopeLock;
    friend class ObjectLock;
    friend class WeakReference;
public:

    Object();
    virtual ~Object();

    inline long AddRef()
    {
        long cRef = AVUI_INTERLOCKED_INCREMENT(m_cRef);

        if(cRef == 1)
        {
            LibraryCriticalErrorMessage("Error -- attempt to addref an object with no references.");
        }

        return cRef;
    }

    inline long Release()
    {
        long cRef = AVUI_INTERLOCKED_DECREMENT(m_cRef);

        if(cRef == 0)
        {
            InvalidateWeakReferences();
            delete this;
        }

        return cRef;
    }

    int get_RefCount() { return m_cRef; };

    virtual bool Equals(const Object* pObject) const;
    virtual const char* ToString() const;

    virtual const Type& get_Type() const { return get_StaticType(); };
    virtual bool IsType(const Type& rhs) const;
    static const Type& get_StaticType();

    static bool Equals(const Object* pObject1, const Object* pObject2);
    static bool ReferenceEquals(const Object* pObject1, const Object* pObject2);

    virtual int GetHashCode() { return (int)this; }

    void* operator new (size_t size); 
    void operator delete (void *p);

    void* operator new[] (size_t size); 
    void operator delete[] (void *p);

    static void* AllocateMemory(size_t size);
    static void FreeMemory(void* p);

    void InvalidateWeakReferences();

    virtual Object* get_Object() { return this; }

private:

    void AddWeakReference(WeakReference* pWeakReference);
    void RemoveWeakReference(WeakReference* pWeakReference);

    void* volatile m_pCriticalSection;
    volatile long m_lockField;
    volatile long m_cRef;
    WeakReference* m_pWeakReferenceFirst;

};

};
